
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window.hpp>
#include <iostream>
#include <vector>

using namespace std;
////////////////////////////////////////////////////////////
/// Ryan Burnside 2011
/// DBF Wireframe comp entry
/// This is my first time using OpenGL with C++ and SFML
////////////////////////////////////////////////////////////



//class for cubes
class Cube
{
public:
    Cube(float x, float y, float z, float width, sf::Window* my_window)
    {
        this->x = x;
        this->y = y;
        this->z = z;
        this->width = width;
        this->my_window = my_window;
    }
    // the cube has a center (x,y,z)
    float x,y,z,width;
    sf::Window* my_window;

};


// function prototypes
void draw_cube();
void draw_list(vector<Cube>& list);
void subdivide_cube(vector<Cube>& list);


int main()
{
    //------------------------------------------------------------------------------------
    sf::Window App(sf::VideoMode(800, 600, 32), "SFML OpenGL ROCKS - Hellot Worlt!");
    // Set color and depth clear value
    glClearDepth(1.f);
    glClearColor(0.f, 0.f, 0.f, 0.f);
    // Enable Z-buffer read and write
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    // Setup a perspective projection
    glMatrixMode(GL_PROJECTION);
    gluPerspective(90.f, 1.f, 1.f, 500.f);

    // Create a clock for measuring time elapsed
    sf::Clock Clock;
    //-------------------------------------------------------------------------------------

    //list of cubes
    vector<Cube> cube_vector;
    cube_vector.push_back(Cube(0.f,0.f,0.f,1.f,&App));
    subdivide_cube(cube_vector);
    subdivide_cube(cube_vector);
    subdivide_cube(cube_vector);
    cout << "Number of cubes " << cube_vector.size() << endl;

    // main loop
    while (App.IsOpened())
    {
        // Process events
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            // Close window : exit
            if (Event.Type == sf::Event::Closed)
                App.Close();

            // Escape key : exit
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                App.Close();

            // Resize event : adjust viewport
            if (Event.Type == sf::Event::Resized)
                glViewport(0, 0, Event.Size.Width, Event.Size.Height);
        }

        // Set the active window before using OpenGL commands
        // It's useless here because active window is always the same,
        // but don't forget it if you use multiple windows or controls
        App.SetActive();

        // Clear color and depth buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Apply some transformations
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.f, 0.f, -1.87);   //<-------------------------------------------------------HERE
        glRotatef(Clock.GetElapsedTime() * 50, 1.f, 0.f, 0.f);
        glRotatef(Clock.GetElapsedTime() * 30, 0.f, 1.f, 0.f);
        glRotatef(Clock.GetElapsedTime() * 90, 0.f, 0.f, 1.f);

        // Draw a cube
        //glPolygonMode(GL_FRONT, GL_LINE);
        glColor4f(0.f, 1.f, 0.f,.5);

        draw_list(cube_vector);

        // Finally, display rendered frame on screen
        App.Display();
    }

    return 0;
}

void draw_list(vector<Cube>& list)
{
    // draws the list

    for(int i = 0; i < list.size(); i++)
    {
        glPushMatrix();
        glTranslatef(list[i].x,list[i].y,list[i].z);
        glScalef(list[i].width, list[i].width, list[i].width);
        draw_cube();
        glPopMatrix();
    }
}

void draw_cube()
{
    glBegin(GL_QUADS);

        glColor3f(0.0f,1.0f,0.0f);
		glVertex3f( .5f, .5f,-.5f);
		glVertex3f(-.5f, .5f,-.5f);
		glVertex3f(-.5f, .5f, .5f);
		glVertex3f( .5f, .5f, .5f);

		glColor3f(1.0f,0.5f,0.0f);
		glVertex3f( .5f,-.5f, .5f);
		glVertex3f(-.5f,-.5f, .5f);
		glVertex3f(-.5f,-.5f,-.5f);
		glVertex3f( .5f,-.5f,-.5f);

		glColor3f(1.0f,0.0f,0.0f);
		glVertex3f( .5f, .5f, .5f);
		glVertex3f(-.5f, .5f, .5f);
		glVertex3f(-.5f,-.5f, .5f);
		glVertex3f( .5f,-.5f, .5f);

		glColor3f(1.0f,1.0f,0.0f);
		glVertex3f( .5f,-.5f,-.5f);
		glVertex3f(-.5f,-.5f,-.5f);
		glVertex3f(-.5f, .5f,-.5f);
		glVertex3f( .5f, .5f,-.5f);

		glColor3f(0.0f,0.0f,1.0f);
		glVertex3f(-.5f, .5f, .5f);
		glVertex3f(-.5f, .5f,-.5f);
		glVertex3f(-.5f,-.5f,-.5f);
		glVertex3f(-.5f,-.5f, .5f);

		glColor3f(1.0f,0.0f,1.0f);
		glVertex3f( .5f, .5f,-.5f);
		glVertex3f( .5f, .5f, .5f);
		glVertex3f( .5f,-.5f, .5f);
		glVertex3f( .5f,-.5f,-.5f);

        glEnd();
}

void subdivide_cube(vector<Cube>& list)
{
    // number of iterations
    int iterations = list.size();
    Cube& first = list.front();
    float new_width = first.width/3.f;

    for(int i = 0; i < iterations; i++)
    {
        Cube c = list.front();
        list.erase(list.begin());
        /* bottom layer 8 cubes drop z back 1/3,
        123
        4 5
        678 */
        list.push_back(Cube(c.x - new_width, c.y - new_width, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x, c.y - new_width, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y - new_width, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x - new_width, c.y, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x - new_width, c.y + new_width, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x, c.y + new_width, c.z-new_width, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y + new_width, c.z-new_width, new_width, c.my_window));

        /* middle layer only 4 new cubes
        10  11

        12  13 */
        list.push_back(Cube(c.x - new_width, c.y - new_width, c.z, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y - new_width, c.z, new_width, c.my_window));
        list.push_back(Cube(c.x - new_width, c.y + new_width, c.z, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y + new_width, c.z, new_width, c.my_window));


        /* bottom layer 8 cubes
        14 15 16
        17    19
        20 21 22 */
        list.push_back(Cube(c.x - new_width, c.y - new_width, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x, c.y - new_width, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y - new_width, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x - new_width, c.y, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x - new_width, c.y + new_width, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x, c.y + new_width, c.z+new_width, new_width, c.my_window));
        list.push_back(Cube(c.x + new_width, c.y + new_width, c.z+new_width, new_width, c.my_window));

        // delete starting cube

    }

}
